﻿//
// Copyright 2024 Exhunter Technology Co.Ltd2.
//

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using X18.Framework.Core.Hash;
using X18.Framework.Core.Utils;

namespace X18.Framework.Core.Security
{
    /// <summary>
    /// 密码加密算法类
    /// </summary>
    public static class PasswordEncryptor
    {
        /// <summary>
        /// 密码加密算法接口函数
        /// </summary>
        private delegate string Confidential(string password, string salt);
        /// <summary>
        /// 密码算法描述字典
        /// </summary>
        private static Dictionary<char, PasswordEncryptType> dictionary;
        /// <summary>
        /// 密码算法函数表
        /// </summary>
        private static Dictionary<PasswordEncryptType, Confidential> confidential;

        static PasswordEncryptor()
        {
            dictionary = Enum.GetValues(typeof(PasswordEncryptType))
                             .Cast<PasswordEncryptType>()
                             .ToDictionary(x => (char)x);
            confidential = new Dictionary<PasswordEncryptType, Confidential>
            {
                { PasswordEncryptType.MurmurHash, GenMurmurHashPassword },
                { PasswordEncryptType.MD5, GenMd5Password },
                { PasswordEncryptType.SHA1, GenSha1Password },
                { PasswordEncryptType.SHA256, GenSha256Password }
            };
        }

        /// <summary>
        /// 生成盐
        /// </summary>
        public static string GenSalt(PasswordEncryptType type = PasswordEncryptType.SHA256)
        {
            if (type.Equals(PasswordEncryptType.MD5))
            {
                return string.Empty;
            }
            else
            {
                string guid = Sequential.SequentialGuid.NewGuid().ToString().Replace("-", "");
                char type0 = (char)type;
                string result = string.Format($"{type0}{guid}");
                return result;
            }
        }

        /// <summary>
        /// 生成哈希密码
        /// </summary>
        /// <param name="password">菜</param>
        /// <returns>编码的菜</returns>
        public static Tuple<string, string> GenPassword(string password)
        {
            string salt = GenSalt();
            string result = GenPassword(password, salt);
            return new Tuple<string, string>(result, salt);
        }
        /// <summary>
        /// 生成哈希密码
        /// </summary>
        /// <param name="password">菜</param>
        /// <param name="salt">盐</param>
        /// <returns>编码的菜</returns>
        public static string GenPassword(string password, string salt)
        {
            if (password.IsEmpty())
            {
                return string.Empty;
            }
            string salt0 = salt;
            PasswordEncryptType type;
            if (salt0.IsEmpty())
            {
                salt0 = string.Empty;
            }
            if (salt0.Length != 33)
            {
                type = PasswordEncryptType.MD5;
                salt0 = string.Empty;
            }
            else
            {
                char key = salt.Substring(0, 1)[0];
                if (dictionary.ContainsKey(key))
                {
                    type = dictionary[key];
                }
                else
                {
                    type = PasswordEncryptType.SHA256;
                }
                salt0 = salt.Substring(1);
            }
            return confidential[type](password, salt0);
        }

        /// <summary>
        /// 生成MurmurHash哈希密码
        /// </summary>
        /// <param name="password">菜</param>
        /// <param name="salt">盐</param>
        /// <returns>编码的菜</returns>
        private static string GenMurmurHashPassword(string password, string salt)
        {
            byte[] bytes1 = Encoding.UTF8.GetBytes(salt);
            byte[] bytes2 = Encoding.UTF8.GetBytes(password);
            int length1 = bytes1.Length;
            int length2 = bytes2.Length;
            byte[] buffer = length1 < length2 ? CombineSecurity(bytes1, bytes2) : CombineSecurity(bytes2, bytes1);
            return MurmurHash.ComputeHashToString(buffer);
        }

        /// <summary>
        /// 生成MD5哈希密码
        /// </summary>
        /// <param name="password">菜</param>
        /// <param name="salt">盐</param>
        /// <returns>编码的菜</returns>
        private static string GenMd5Password(string password, string salt)
        {
            byte[] bytes1 = Encoding.UTF8.GetBytes(salt);
            byte[] bytes2 = Encoding.UTF8.GetBytes(password);
            int length1 = bytes1.Length;
            int length2 = bytes2.Length;
            byte[] buffer = length1 < length2 ? CombineSecurity(bytes1, bytes2) : CombineSecurity(bytes2, bytes1);
            return Md5.ComputeHashToString(buffer);
        }

        /// <summary>
        /// 生成SHA1哈希密码
        /// </summary>
        /// <param name="password">菜</param>
        /// <param name="salt">盐</param>
        /// <returns>编码的菜</returns>
        private static string GenSha1Password(string password, string salt)
        {
            byte[] bytes1 = Encoding.UTF8.GetBytes(salt);
            byte[] bytes2 = Encoding.UTF8.GetBytes(password);
            int length1 = bytes1.Length;
            int length2 = bytes2.Length;
            byte[] buffer = length1 < length2 ? CombineSecurity(bytes1, bytes2) : CombineSecurity(bytes2, bytes1);
            return Sha1.ComputeHashToString(buffer);
        }

        /// <summary>
        /// 生成SHA256哈希密码
        /// </summary>
        /// <param name="password">菜</param>
        /// <param name="salt">盐</param>
        /// <returns>编码的菜</returns>
        private static string GenSha256Password(string password, string salt)
        {
            byte[] bytes1 = Encoding.UTF8.GetBytes(salt);
            byte[] bytes2 = Encoding.UTF8.GetBytes(password);
            int length1 = bytes1.Length;
            int length2 = bytes2.Length;
            byte[] buffer = length1 < length2 ? CombineSecurity(bytes1, bytes2) : CombineSecurity(bytes2, bytes1);
            return Sha256.ComputeHashToString(buffer);
        }

        /// <summary>
        /// 加盐
        /// </summary>
        private static byte[] CombineSecurity(byte[] bytes1, byte[] bytes2)
        {
            byte[] result = new byte[bytes1.Length + bytes2.Length];
            int index;
            for (index = 0; index < bytes1.Length; index++)
            {
                result[index * 2] = bytes1[index];
                result[index * 2 + 1] = bytes2[index];
            }
            int index0 = index * 2;
            for (; index < bytes2.Length; index++)
            {
                result[index0++] = bytes2[index];
            }
            return result;
        }
    }

    /// <summary>
    /// 密码加密算法类型
    /// </summary>
    public enum PasswordEncryptType
    {
        MurmurHash = '0',
        MD5 = '5',
        SHA1 = '1',
        SHA256 = '6',
    }
}
